From c00cc269c5be8537a0ae5a37991e2c8ffc918d81 Mon Sep 17 00:00:00 2001 From: Michael Natterer Date: Mon, 15 Dec 2014 11:25:43 +0000 Subject: [PATCH] broadway: Initial SSL support Use the new --cert and --key parameters to broadwayd to pass paths to cert and key files. https://bugzilla.gnome.org/show_bug.cgi?id=730364 --- gdk/broadway/broadway-server.c | 90 +++++++++++++++++++++++++++------- gdk/broadway/broadway-server.h | 2 + gdk/broadway/broadwayd.c | 10 +++- 3 files changed, 83 insertions(+), 19 deletions(-) diff --git a/gdk/broadway/broadway-server.c b/gdk/broadway/broadway-server.c index 8ee4b59d38..547729fa27 100644 --- a/gdk/broadway/broadway-server.c +++ b/gdk/broadway/broadway-server.c @@ -42,6 +42,8 @@ struct _BroadwayServer { char *address; int port; + char *ssl_cert; + char *ssl_key; GSocketService *service; BroadwayOutput *output; guint32 id_counter; @@ -85,7 +87,8 @@ struct _BroadwayServerClass typedef struct HttpRequest { BroadwayServer *server; - GSocketConnection *connection; + GSocketConnection *socket_connection; + GIOStream *connection; GDataInputStream *data; GString *request; } HttpRequest; @@ -93,7 +96,7 @@ typedef struct HttpRequest { struct BroadwayInput { BroadwayServer *server; BroadwayOutput *output; - GSocketConnection *connection; + GIOStream *connection; GByteArray *buffer; GSource *source; gboolean seen_time; @@ -155,6 +158,8 @@ broadway_server_finalize (GObject *object) BroadwayServer *server = BROADWAY_SERVER (object); g_free (server->address); + g_free (server->ssl_cert); + g_free (server->ssl_key); G_OBJECT_CLASS (broadway_server_parent_class)->finalize (object); } @@ -172,6 +177,7 @@ static void start (BroadwayInput *input); static void http_request_free (HttpRequest *request) { + g_object_unref (request->socket_connection); g_object_unref (request->connection); g_object_unref (request->data); g_string_free (request->request, TRUE); @@ -661,14 +667,13 @@ broadway_server_read_all_input_nonblocking (BroadwayInput *input) GInputStream *in; gssize res; guint8 buffer[1024]; - GError *error; + GError *error = NULL; if (input == NULL) return; - in = g_io_stream_get_input_stream (G_IO_STREAM (input->connection)); + in = g_io_stream_get_input_stream (input->connection); - error = NULL; res = g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM (in), buffer, sizeof (buffer), NULL, &error); @@ -796,7 +801,8 @@ broadway_server_block_for_input (BroadwayServer *server, char op, /* Not found, read more, blocking */ - in = g_io_stream_get_input_stream (G_IO_STREAM (input->connection)); + in = g_io_stream_get_input_stream (input->connection); + res = g_input_stream_read (in, buffer, sizeof (buffer), NULL, NULL); if (res <= 0) return NULL; @@ -909,9 +915,11 @@ send_error (HttpRequest *request, error_code, reason, error_code, reason, reason); + /* TODO: This should really be async */ - g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)), - res, strlen (res), NULL, NULL, NULL); + g_output_stream_write_all (g_io_stream_get_output_stream (request->connection), + res, strlen (res), NULL, NULL, NULL); + g_free (res); http_request_free (request); } @@ -1004,8 +1012,8 @@ start_input (HttpRequest *request) g_print ("v7 proto response:\n%s", res); #endif - g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)), - res, strlen (res), NULL, NULL, NULL); + g_output_stream_write_all (g_io_stream_get_output_stream (request->connection), + res, strlen (res), NULL, NULL, NULL); g_free (res); } else @@ -1015,7 +1023,7 @@ start_input (HttpRequest *request) return; } - socket = g_socket_connection_get_socket (request->connection); + socket = g_socket_connection_get_socket (request->socket_connection); setsockopt (g_socket_get_fd (socket), IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); @@ -1028,12 +1036,13 @@ start_input (HttpRequest *request) g_byte_array_append (input->buffer, data_buffer, data_buffer_size); input->output = - broadway_output_new (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)), 0); + broadway_output_new (g_io_stream_get_output_stream (request->connection), 0); /* This will free and close the data input stream, but we got all the buffered content already */ http_request_free (request); - in = g_io_stream_get_input_stream (G_IO_STREAM (input->connection)); + in = g_io_stream_get_input_stream (input->connection); + input->source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (in), NULL); g_source_set_callback (input->source, (GSourceFunc)input_data_cb, input, NULL); g_source_attach (input->source, NULL); @@ -1101,11 +1110,12 @@ send_data (HttpRequest *request, "Content-Length: %"G_GSIZE_FORMAT"\r\n" "\r\n", mimetype, len); + /* TODO: This should really be async */ - g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)), + g_output_stream_write_all (g_io_stream_get_output_stream (request->connection), res, strlen (res), NULL, NULL, NULL); g_free (res); - g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)), + g_output_stream_write_all (g_io_stream_get_output_stream (request->connection), data, len, NULL, NULL, NULL); http_request_free (request); } @@ -1202,11 +1212,49 @@ handle_incoming_connection (GSocketService *service, GInputStream *in; request = g_new0 (HttpRequest, 1); - request->connection = g_object_ref (connection); + request->socket_connection = g_object_ref (connection); request->server = BROADWAY_SERVER (source_object); request->request = g_string_new (""); - in = g_io_stream_get_input_stream (G_IO_STREAM (connection)); + if (request->server->ssl_cert && request->server->ssl_key) + { + GError *error = NULL; + GTlsCertificate *certificate; + + certificate = g_tls_certificate_new_from_files (request->server->ssl_cert, + request->server->ssl_key, + &error); + if (!certificate) + { + g_warning ("Cannot create TLS certificate: %s", error->message); + g_error_free (error); + return FALSE; + } + + request->connection = g_tls_server_connection_new (G_IO_STREAM (connection), + certificate, + &error); + if (!request->connection) + { + g_warning ("Cannot create TLS connection: %s", error->message); + g_error_free (error); + return FALSE; + } + + if (!g_tls_connection_handshake (G_TLS_CONNECTION (request->connection), + NULL, &error)) + { + g_warning ("Cannot create TLS connection: %s", error->message); + g_error_free (error); + return FALSE; + } + } + else + { + request->connection = g_object_ref (connection); + } + + in = g_io_stream_get_input_stream (request->connection); request->data = g_data_input_stream_new (in); g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (request->data), FALSE); @@ -1219,7 +1267,11 @@ handle_incoming_connection (GSocketService *service, } BroadwayServer * -broadway_server_new (char *address, int port, GError **error) +broadway_server_new (char *address, + int port, + const char *ssl_cert, + const char *ssl_key, + GError **error) { BroadwayServer *server; GInetAddress *inet_address; @@ -1228,6 +1280,8 @@ broadway_server_new (char *address, int port, GError **error) server = g_object_new (BROADWAY_TYPE_SERVER, NULL); server->port = port; server->address = g_strdup (address); + server->ssl_cert = g_strdup (ssl_cert); + server->ssl_key = g_strdup (ssl_key); if (address == NULL) { diff --git a/gdk/broadway/broadway-server.h b/gdk/broadway/broadway-server.h index cbe656ed28..b5d319133a 100644 --- a/gdk/broadway/broadway-server.h +++ b/gdk/broadway/broadway-server.h @@ -21,6 +21,8 @@ typedef struct _BroadwayServerClass BroadwayServerClass; BroadwayServer *broadway_server_new (char *address, int port, + const char *ssl_cert, + const char *ssl_key, GError **error); BroadwayServer *broadway_server_on_unix_socket_new (char *address, GError **error); diff --git a/gdk/broadway/broadwayd.c b/gdk/broadway/broadwayd.c index 031e866b00..e1a0fc8a0b 100644 --- a/gdk/broadway/broadwayd.c +++ b/gdk/broadway/broadwayd.c @@ -419,6 +419,8 @@ main (int argc, char *argv[]) char *http_address = NULL; char *unixsocket_address = NULL; int http_port = 0; + char *ssl_cert = NULL; + char *ssl_key = NULL; char *display; int port = 0; const GOptionEntry entries[] = { @@ -427,6 +429,8 @@ main (int argc, char *argv[]) #ifdef G_OS_UNIX { "unixsocket", 'u', 0, G_OPTION_ARG_STRING, &unixsocket_address, "Unix domain socket address", "ADDRESS" }, #endif + { "cert", 'c', 0, G_OPTION_ARG_STRING, &ssl_cert, "SSL certificate path", "PATH" }, + { "key", 'k', 0, G_OPTION_ARG_STRING, &ssl_key, "SSL key path", "PATH" }, { NULL } }; @@ -493,7 +497,11 @@ main (int argc, char *argv[]) if (unixsocket_address != NULL) server = broadway_server_on_unix_socket_new (unixsocket_address, &error); else - server = broadway_server_new (http_address, http_port, &error); + server = broadway_server_new (http_address, + http_port, + ssl_cert, + ssl_key, + &error); if (server == NULL) { -- 2.30.2